/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package pt.mleiria.skip;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.text.MessageFormat;
import javax.crypto.KeyAgreement;
import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import pt.mleiria.algorithm.KeyExchange;
import pt.mleiria.generator.KeyPairGen;

/**
 *
 * @author NB13712
 */
public class SkipClient {
    public static final String host = "127.0.0.1";
    public static final int port = 69;
    private static final Logger LOG = Logger.getLogger(SkipClient.class);
    private static KeyPair keyPair;
    private static byte[] secret;

    public static void  start() throws IOException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeySpecException, InvalidKeyException {
        //Create a Diffie-Hellman Key pair
        final KeyPairGen kpg = new KeyPairGen(KeyExchange.DH.value(), Skip.sDHParameterSpec);
        keyPair = kpg.getKeyPair();
        //Open the network connection
        LOG.info("Connecting to Server:" + host + ":" + port);
        final Socket s = new Socket(host, port);
        LOG.info("Connected!");
        final DataOutputStream out = new DataOutputStream(s.getOutputStream());
        final DataInputStream in = new DataInputStream(s.getInputStream());
        sendPublicKey(out);
        LOG.info("Public key sent to server.");
        final PublicKey theirPublicKey = receivePublicKey(in);
        LOG.info("Public key received from server.");
        generateSecretValue(theirPublicKey);
    }
    
    private static void sendPublicKey(final DataOutputStream out) throws IOException{
        final byte[] keyBytes = keyPair.getPublic().getEncoded();
        out.writeInt(keyBytes.length);
        out.write(keyBytes);
    }
    private static PublicKey receivePublicKey(final DataInputStream in) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException{
        final byte[] keyBytes = new byte[in.readInt()];
        in.readFully(keyBytes);
        final KeyFactory kf = KeyFactory.getInstance(KeyExchange.DH.value());
        final X509EncodedKeySpec x509Spec = new X509EncodedKeySpec(keyBytes);
        final PublicKey theirPublicKey = kf.generatePublic(x509Spec);
        return theirPublicKey;
    }
    
    private static void generateSecretValue(final PublicKey theirPublicKey) throws NoSuchAlgorithmException, InvalidKeyException{
        final KeyAgreement ka = KeyAgreement.getInstance(KeyExchange.DH.value());
        ka.init(keyPair.getPrivate());
        ka.doPhase(theirPublicKey, true);
        secret = ka.generateSecret();
        //LOG.info(MessageFormat.format("Secret value generated by SkipClient:{0}", new String(Base64.encodeBase64(secret)), "UTF-8"));
    }
    
    public static byte[] getSecret(){
        return secret;
    }
    
}
